package cn.bupt.adt.controller.inf;

import cn.bupt.adt.component.ReturnHelper;
import cn.bupt.adt.constant.Constants;
import cn.bupt.adt.entity.autogenerate.*;
import cn.bupt.adt.model.OperationContent;
import cn.bupt.adt.service.*;
import cn.bupt.adt.service.impl.DoctorAppUserService;
import cn.bupt.adt.util.*;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Controller
@RequestMapping("/interface/institution/order")
@Transactional(rollbackFor = {MySQLIntegrityConstraintViolationException.class})
public class PublishOrderController {

    @Autowired
    IInstitutionAppUserService institutionAppUserService;
    @Autowired
    IOrderService orderService;

    @Autowired
    IDoctorService doctorService;

    @Autowired
    IInstitutionService institutionService;

    @Autowired
    IinspectOrderService inspectOrderService;

    @Autowired
    ObjectMapper objectMapper;

    @Autowired
    ReturnHelper returnHelper;

    @Autowired
    DoctorAppUserService doctorAppUserService;

    @Autowired
    private IFeeConfService feeConfService;

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));// true:允许输入空值，false:不能为空值
    }

    private boolean isSame(double money, List<OperationContent> operationContents) {
        double sum = 0.0;
        for (OperationContent op : operationContents)
            sum += op.getMoney();
        return Math.abs(sum - money) < 0.1;
    }

    /**
     * 发布订单
     * <p>
     * operationTypeId 手术类型id
     * startTime 预计开始时间
     * estimatedCostTime 预计耗时
     */
    @RequestMapping(value = "/publishOrder", method = RequestMethod.POST)
    @ResponseBody
    public Object publishOrder(HttpServletRequest request, @Valid Order order, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return NetDataAccessUtil.error(5).resultDesp(bindingResult.getAllErrors().iterator().next().getDefaultMessage());
        }
        Integer userId = (Integer) request.getAttribute("userId");
        List<OperationContent> operationContents;
        try {
            operationContents = objectMapper.readValue(order.getOperationContent(), new TypeReference<List<OperationContent>>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
            return NetDataAccessUtil.error(0).resultDesp("operationContent参数传递形式有错误，请检查");
        }
        if (order.getNum() > 5 || operationContents.size() != order.getNum())
            return NetDataAccessUtil.error(4).resultDesp("手术数量超过5个或者填写的数量与实际的手术数量不一致");
        if (!isSame(order.getMoney(), operationContents))
            return NetDataAccessUtil.error(7).resultDesp("订单money与实际各手术money加起来不一致");
        // if (ins.getMoney() < order.getMoney()) {
        // nau.setContent(null);
        // nau.setResult(3);
        // nau.setResultDesp("余额不足，无法发布该金额的订单，请先充值");
        // return nau;
        // } else {
        // ins.setMoney(ins.getMoney() - order.getMoney());
        // institutionAppUserService.updateInstitutionAppUser(ins);
        // }此处机构的金额先不扣除，也不检测是否够订单费用
        Date date = new Date();
        order.setInstitutionId(userId);
        order.setPublicTime(date);
        order.setStatus(0);
        order.setPublishStatus(0);
        if (orderService.addOrder(order, doctorService)) {
            Order or = new Order();
            or.setId(order.getId());
            or.setOrderNo(DateUtil.formatDate(Constants.ORDER_PREFIX, date) + order.getId());
            orderService.updateOrderByPrimarykeySelective(or);
            return NetDataAccessUtil.success().resultDesp("发布订单成功");
        }
        return NetDataAccessUtil.error(2).resultDesp("因网络或其他原因发布订单失败，请稍后尝试");
    }

    @RequestMapping(value = "/updateOrder", method = RequestMethod.POST)
    @ResponseBody
    // 机构发布订单需要填写金额money，手术类型operationTypeId,手术预计开始时间startTime，手术预计耗时estimatedCostTime
    public Object updateOrder(HttpServletRequest request, @Valid Order order, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return returnHelper.returnNau(null, 5, bindingResult.getAllErrors().iterator().next().getDefaultMessage());
        }
        if (order.getId() == null)
            return returnHelper.returnNau(null, 6, "请传入订单id");
        if (order.getDoctorId() != null && order.getDoctorId() != -1)
            return returnHelper.returnNau(null, 9, "不要传入doctorId");
        NetDataAccessUtil nau = new NetDataAccessUtil();
        Integer userId = (Integer) request.getAttribute("userId");
        InstitutionAppUser ins = institutionAppUserService.getInstitutionById(userId);
        List<OperationContent> operationContents;
        try {
            operationContents = objectMapper.readValue(order.getOperationContent(),
                    new TypeReference<List<OperationContent>>() {
                    });
        } catch (IOException e) {
            e.printStackTrace();
            return returnHelper.returnNau(null, 0, "operationContent参数传递形式有错误，请检查");
        }
        if (order.getNum() > 5 || operationContents.size() != order.getNum())
            return returnHelper.returnNau(null, 4, "手术数量超过5个或者填写的数量与实际的手术数量不一致");
        if (!isSame(order.getMoney(), operationContents))
            return returnHelper.returnNau(null, 7, "订单money与实际各手术money加起来不一致");
        Order old = orderService.getOrderById(order.getId());
        if (!old.getInstitutionId().equals(userId))
            return returnHelper.returnNau(null, 9, "该订单不属于该机构，不能修改");
        if (!old.getStatus().equals(Constants.ORDER_STATUS_TAKEDNOTOPER)
                && !old.getStatus().equals(Constants.ORDER_STATUS_BIANDONG))
            return returnHelper.returnNau(null, 8, "该订单并非已接单未开始手术，不能修改");

        if (old.getMoney() < order.getMoney()) {
            if (ins.getMoney() < order.getMoney() - old.getMoney()) {
                nau.setContent(null);
                nau.setResult(3);
                nau.setResultDesp("修改的订单金额超过之前订单的金额，而余额不足，无法修改订单，请先充值");
                return nau;
            } else {
                ins.setMoney(ins.getMoney() - (order.getMoney() - old.getMoney()));
                institutionAppUserService.updateInstitutionAppUser(ins);
            }
        }
        Date date = new Date();
        order.setInstitutionId(userId);
        order.setPublicTime(date);
        order.setStatus(7);
        orderService.updateOrderByPrimarykeySelective(order);
        SendSMSUtil sendSMSUtil = new SendSMSUtil();
        DoctorAppUser doc = doctorAppUserService.getDoctorById(old.getDoctorId());
        sendSMSUtil.SendSMS(doc.getPhone(), new String[]{doc.getName(), old.getOrderNo()},
                Constants.SMS_BIANDONG_INFORM);
        nau.setContent(null);
        nau.setResult(1);
        nau.setResultDesp("修改订单成功");

        return nau;
    }

    @RequestMapping(value = "/publishInspectOrder", method = RequestMethod.POST)
    @ResponseBody
    // 机构发布检查项目订单，需要填写检查项目数量
    public Object publishOrder(HttpServletRequest request, String orderMessage) {
        NetDataAccessUtil nau = new NetDataAccessUtil();
        Integer userId = (Integer) request.getAttribute("userId");
        InstitutionAppUser ins = institutionAppUserService.getInstitutionById(userId);
        List<InspectOrder> orders = null;
        try {
            orders = new ObjectMapper().readValue(orderMessage, new TypeReference<List<InspectOrder>>() {
            });
        } catch (IOException e) {
            nau.setContent(null);
            nau.setResult(0);
            nau.setResultDesp("orderMessage格式不对");
            return nau;
        }
        double sum = 0.0;
        for (InspectOrder order : orders) {
            Inspetion inspetion = inspectOrderService.getInspetionByChecckId(order.getCheckId());
            if (inspetion == null) {
                nau.setContent(null);
                nau.setResult(0);
                nau.setResultDesp("checkId不存在，请检查");
                return nau;
            }
            double money = order.getNumber() * inspetion.getFeescale();
            sum += money;
            if (sum > ins.getMoney()) {
                nau.setContent(null);
                nau.setResult(0);
                nau.setResultDesp("余额不足，无法发布该金额的订单，请先充值");
                return nau;
            }
            order.setMoney(money);
            order.setTime(new Date());
            order.setStatus(0);
            order.setInstitutionId(userId);
            order.setInstitutionName(institutionService.getInstitutionNameById(userId));
            order.setName(inspetion.getName());
            order.setInspectionId(inspetion.getId());
        }
        ins.setMoney(ins.getMoney() - sum);
        institutionAppUserService.updateInstitutionAppUser(ins);
        if (inspectOrderService.addOrder(orders)) {
            nau.setContent(null);
            nau.setResult(1);
            nau.setResultDesp("发布检查项目订单成功");
        } else {
            nau.setContent(null);
            nau.setResult(0);
            nau.setResultDesp("因网络或其他原因发布订单失败，请稍后尝试");
        }
        return nau;
    }

    @RequestMapping(value = "/getOperationType", method = RequestMethod.POST)
    @ResponseBody
    public Object getOperationType(HttpServletRequest request) {
        NetDataAccessUtil nau = new NetDataAccessUtil();
        List<OperationType> types = doctorService.getAllOpertionType();
        nau.setContent(types);
        nau.setResult(1);
        nau.setResultDesp("获取手术类别成功");
        return nau;
    }

    @RequestMapping(value = "/getSubOperationType", method = RequestMethod.POST)
    @ResponseBody
    public Object getSubOperationType(HttpServletRequest request) {
        NetDataAccessUtil nau = new NetDataAccessUtil();
        List<SubOperationType> types = doctorService.getAllSubOpertionType();
        nau.setContent(types);
        nau.setResult(1);
        nau.setResultDesp("获取二级手术类别成功");
        return nau;
    }

    @RequestMapping(value = "/getSubOperationTypeByParentId", method = RequestMethod.POST)
    @ResponseBody
    public Object getSubOperationTypeByParentId(HttpServletRequest request, int parentId) {
        NetDataAccessUtil nau = new NetDataAccessUtil();
        List<SubOperationType> types = doctorService.getSubOperationTypeByParentId(parentId);
        nau.setContent(types);
        nau.setResult(1);
        nau.setResultDesp("获取二级手术类别成功");
        return nau;
    }

    /**
     * 机构查询订单列表
     */
    @RequestMapping(value = "/getPublicshedOrders", method = RequestMethod.POST)
    @ResponseBody
    // 机构获取发布的订单,status传0表示希望获取未接单的订单,1表示进行中，2表示历史订单
    public Object getPublicshedOrders(HttpServletRequest request, Integer pageSize, Integer pageNum, Integer status) throws IllegalAccessException, IOException {
        NetDataAccessUtil nau = new NetDataAccessUtil();
        Integer userId = (Integer) request.getAttribute("userId");
        Page<?> page = PageHelper.startPage(pageNum, pageSize);
        List<OrderView> lists = orderService.getOrderByInstitutionIdAndStatus(userId, status);
        List<Map<String, Object>> res = new ArrayList<>(lists.size());
        for (OrderView or : lists) {
            or.setPortrait(request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/"
                    + Constants.IMAGE_PATH + or.getPortrait());
            String operationContent = or.getOperationContent();
            if (operationContent != null && operationContent.length() > 2) {
                Map<String, Object> orderModel = BeanUtil.beanToMap(or);
                orderModel.put("operationContent",
                        objectMapper.readValue(or.getOperationContent(), new TypeReference<List<OperationContent>>() {
                        }));
                res.add(orderModel);
            }
        }
        Map<String, Object> content = new HashMap<>();
        content.put("orders", res);
        content.put("currentPage", page.getPageNum());
        content.put("allPages", page.getPages());
        nau.setContent(content);
        nau.setResult(1);
        nau.setResultDesp("获取发布订单成功");
        return nau;
    }

    // 更改订单状态,变5取消订单。0机构取消,1医生取消（订单号、取消方，取消原因）
    @RequestMapping("/cancelOrderByInsti")
    @ResponseBody
    public Object cancelOrderByInsti(HttpServletRequest request, Order order) {
        NetDataAccessUtil nau = new NetDataAccessUtil();
        if (orderService.getOrderById(order.getId()).getStatus() == 0) {
            boolean rst = orderService.cancelOrderByInst(order);
            if (rst) {
                nau.setResult(1);
                nau.setResultDesp("机构取消订单成功");
            } else {
                nau.setResult(0);
                nau.setResultDesp("机构取消订单失败");
            }
        } else {
            nau.setResult(0);
            nau.setResultDesp("已有人接单不能取消订单");
        }
        return nau;
    }

    // 更改订单状态,机构确认手术结束
    @RequestMapping("/affirmOrder")
    @ResponseBody
    public Object changeOrderStatus(HttpServletRequest request, Order order) {
        boolean rst = orderService.instiUpdateOrder(order);
        NetDataAccessUtil nau = new NetDataAccessUtil();
        if (rst) {
            nau.setResult(1);
            nau.setResultDesp("确认手术结束成功");
        } else {
            nau.setResult(0);
            nau.setResultDesp("确认手术结束失败");
        }
        return nau;
    }

    // 机构获取订单详情
    @RequestMapping("/getInstiOrderDetail")
    @ResponseBody
    public Object getInstiOrderDetail(HttpServletRequest request, OrderView order)
            throws IllegalArgumentException, IllegalAccessException {
        OrderView orderList = orderService.getOrderViewById(order.getId());
        if (orderList == null)
            return returnHelper.returnNau(null, 0, "暂无对应订单");
        Map<String, Object> or = BeanUtil.beanToMap(orderList);
        try {
            or.put("operationContent", objectMapper.readValue(orderList.getOperationContent(),
                    new TypeReference<List<OperationContent>>() {
                    }));
            or.put("portrait", ImageUtil.contructFullImagePath(orderList.getPortrait(), request));
        } catch (IOException e) {
            e.printStackTrace();
            returnHelper.returnNau(null, 0, "获取订单详情失败");
        }
        return returnHelper.returnNau(or, 1, "获取订单详情成功");

    }

    /**
     * 计算订单中的手术总金额
     *
     * @param hours
     * @return
     */
    @RequestMapping("/getTotalPrice")
    @ResponseBody
    public Object getTotalPrice(BigDecimal hours, Integer institutionId) {
        if (hours == null) {
            return NetDataAccessUtil.error().resultDesp("未填写手术预计时间");
        }
        if (institutionId == null) {
            return NetDataAccessUtil.error().resultDesp("缺少机构id参数");
        }
        FeeConf feeConf = feeConfService.selectByInstitutionId(institutionId);
        BigDecimal sum = hours.multiply(feeConf.getUnitPrice())
                .add(feeConf.getBase())
                .add(feeConf.getEmergency())
                .add(feeConf.getCompl())
                .add(feeConf.getSpecial());
        return NetDataAccessUtil.success().content(sum).resultDesp("计算总价成功");
    }

}
